require 'hmac-sha1'
require 'digest/md5'
require 'base64'

module API::V3
  class AuthTokens < Grape::API
    helpers do
      # generate secure identify algorithm
      def generate_secure_identify mac, timestamp
        # strip `:` in mac address and then reverse it
        reverse_mac = mac.delete(':').reverse
        # transfer the first and last half of it
        exchange_mac = reverse_mac[6..11] + reverse_mac[0..5]
        # generate a number array based on timestamp to perform sort
        sort_weight = Digest::MD5.hexdigest(timestamp.to_s)[0..23].chars.each_slice(2).map { |s| s.join.to_i 16 }
        # then sort it
        index = -1
        sort_mac = exchange_mac.chars.to_a.sort_by! { |k| sort_weight[index += 1] + index.to_f/100 }.join
        # hmac-sha1
        result = Base64.urlsafe_encode64(HMAC::SHA1.digest(private_key, sort_mac)).strip

        # log the every variables
        local_variables.each do |var|
          DebugLog.add_to_log var => eval(var.to_s)
        end

        result
      end

      # generate private key
      def private_key
        key_file = Rails.root.join('.private_key')
        if File.exist?(key_file)
          # Use the existing token.
          File.read(key_file).chomp
        else
          # Generate a new token and store it in key_file.
          token = SecureRandom.hex(64)
          File.write(key_file, token)
          token
        end
      end
    end

    resource :auth_tokens do
      params do
        requires :mac, type: String, regexp: /\A([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}\z/
        requires :timestamp, type: Integer
        requires :result, type: String
        requires :client_type, type: String, values: ['app', 'terminal']
      end
      post do
        if (params[:timestamp] - Time.now.to_i).abs > 3 * 60
          present :result, false
          present :error_code, 1
          present :message, "the timestamp is out-of-date"
          present :timestamp, Time.now.to_i
        elsif generate_secure_identify(params[:mac], params[:timestamp]) == params[:result]
          auth_token = AuthToken.create(client_identifier: params[:mac], client_type: params[:client_type])
          present :result, true
          present :client_id, auth_token.id
          present :auth_token, auth_token.token
        else
          present :result, false
          present :error_code, 2
          present :message, "the result doesn't match"
        end

      end

    end
  end
end